package com.mapforge.gui.map;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import com.mapforge.InputMapping;
import com.mapforge.gui.JPopupMenuProvider;
import com.mapforge.gui.interfaces.TileMapEditorGUIInterface;
import com.mapforge.map.TileMap;

/**
 * The {@link TileMapEditorGUIMouseListener} class listens to mouse motion
 * events, and normal mouse events by extending {@link MouseAdapter}. It helps
 * control when a {@link TileMapEditorGUIInterface} should render its contents
 * to the screen.
 * 
 * @author Will Morrison
 * 
 */
public class TileMapEditorGUIMouseListener extends MouseAdapter {
	/**
	 * {@link TileMapEditorGUIInterface} this
	 * {@link TileMapEditorGUIMouseListener} is helping to render.
	 */
	private TileMapEditorGUIInterface guiInterface;
	private JPopupMenuProvider<TileMapEditorGUIInterface> guiPopupProvider;
	private boolean mouseDown;
	private Point lastKnownPoint;

	public TileMapEditorGUIMouseListener(
			TileMapEditorGUIInterface guiInterface,
			JPopupMenuProvider<TileMapEditorGUIInterface> provider) {
		this.guiInterface = guiInterface;
		this.mouseDown = false;
		this.lastKnownPoint = new Point();
		this.guiPopupProvider = provider;
	}

	private Point tileAt(Point p) {
		return tileAt(p.x, p.y);
	}

	/**
	 * Returns the current tile x and y locations relative to an x and y
	 * location.
	 * 
	 * @param x
	 *            x location
	 * @param y
	 *            y location
	 * @return the x and y location of the current tile
	 */
	private Point tileAt(int x, int y) {
		TileMap tileMap = guiInterface.getTiledMap();
		if (tileMap != null) {
			int w = tileMap.getWidth();
			int h = tileMap.getHeight();
			if (x < tileMap.getX() || x > tileMap.getX() + w
					|| y < tileMap.getY() || y > tileMap.getY() + h) {
				return null;
			}
			Point tileAt = new Point();
			tileAt.x = (int) ((tileMap.getX() + x) / tileMap.getTileWidth());
			tileAt.y = (int) ((tileMap.getY() + y) / tileMap.getTileHeight());
			return tileAt;
		} else {
			return null;
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
		// mouseInBounds = true;
	}

	public void mouseExited(MouseEvent e) {
		// mouseInBounds = false;
		this.guiInterface.repaint();
	}

	public void mousePressed(MouseEvent e) {
		if (e.getButton() != InputMapping.POPUP_TRIGGER && !mouseDown) {
			mouseDown = true;
			this.guiInterface.repaint();
		}
	}

	/**
	 * Called when mouse is released. Releasing the mouse will cause the
	 * currently active tool to attempt to perform an edit on the currently
	 * selected layer.
	 */
	public void mouseReleased(MouseEvent e) {
		if (e.getButton() != InputMapping.POPUP_TRIGGER) {
			mouseDown = false;
			this.guiInterface.repaint();
		}
	}

	public void mouseDragged(MouseEvent e) {
		if (e.getButton() != InputMapping.POPUP_TRIGGER) {
			TileMap tileMap = this.guiInterface.getTiledMap();
			if (tileMap != null) {
				Point p = tileAt(e.getPoint());
				if (p != null) {
					if (lastKnownPoint.x != p.x || lastKnownPoint.y != p.y) {
						lastKnownPoint.x = p.x;
						lastKnownPoint.y = p.y;
						Rectangle r = new Rectangle(e.getX(), e.getY(), tileMap
								.getTileWidth(), tileMap.getTileHeight());
						this.guiInterface.scrollRectToVisible(r);
						this.guiInterface.repaint();
					}
				}
			}
		}

	}

	public void mouseMoved(MouseEvent e) {
		if (this.guiInterface.getTiledMap() != null) {
			Point p = tileAt(e.getPoint());
			if (p != null) {
				if (lastKnownPoint.x != p.x || lastKnownPoint.y != p.y) {
					lastKnownPoint.x = p.x;
					lastKnownPoint.y = p.y;
				}
			}
			this.guiInterface.repaint();
		}
	}
}
